package com.gemantic.glue.exec;

import java.util.Date;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.gemantic.glue.context.GlueExecContext;
import com.gemantic.glue.enums.GlueTypeEnum;
import com.gemantic.glue.exec.context.GlueExecutor;
import com.gemantic.glue.factory.GlueFactory;
import com.gemantic.glue.handler.GlueHandler;
import com.gemantic.glue.handler.IGlueHandler;
import com.gemantic.glue.handler.ScriptGlueHandler;
import com.gemantic.glue.log.JobFileAppender;
import com.gemantic.glue.model.LogParam;
import com.gemantic.glue.model.LogResult;
import com.gemantic.glue.model.ReturnT;
import com.gemantic.glue.model.TriggerParam;


/**
 * Created by xuxueli on 17/3/1.
 */
public class ExecutorBizImpl {
    private static Logger logger = LoggerFactory.getLogger(ExecutorBizImpl.class);

    public ReturnT<ConcurrentMap<String,Object>> run(TriggerParam triggerParam) {
        ExecutorHandler executorHandler =  triggerParam.isReuse() ? GlueExecutor.loadJobThread(triggerParam.getJobId()) : null;
        IGlueHandler jobHandler = executorHandler != null ? executorHandler.getHandler() : null;
        String removeOldReason = null;
        GlueTypeEnum glueTypeEnum = GlueTypeEnum.match(triggerParam.getGlueType());
        String logFileName = JobFileAppender.makeLogFileName(new Date(System.currentTimeMillis()), triggerParam.getLogId());

        if (GlueTypeEnum.BEAN == glueTypeEnum) {

            // new jobhandler
            IGlueHandler newJobHandler = GlueExecutor.loadJobHandler(triggerParam.getExecutorHandler());

            // valid old jobThread
            if (executorHandler != null && jobHandler != newJobHandler) {
                // change handler, need kill old thread
                removeOldReason = "change jobhandler or glue type, and terminate the old job thread.";
                executorHandler = null;
                jobHandler = null;
            }

            // valid handler
            if (jobHandler == null) {
                jobHandler = newJobHandler;
                if (jobHandler == null) {
                    return new ReturnT<>(ReturnT.FAIL_CODE, "job handler [" + triggerParam.getExecutorHandler() + "] not found.");
                }
            }

        } else if (GlueTypeEnum.GLUE_GROOVY == glueTypeEnum) {

            // valid old jobThread
            if (executorHandler != null && !(executorHandler.getHandler() instanceof GlueHandler && ((GlueHandler) executorHandler.getHandler()).getGlueUpdatetime() == triggerParam.getGlueUpdatetime())) {
                // change handler or gluesource updated, need kill old thread
                removeOldReason = "change job source or glue type, and terminate the old job thread.";
                executorHandler = null;
                jobHandler = null;
            }

            // valid handler
            if (jobHandler == null) {
                try {
                    IGlueHandler originJobHandler = GlueFactory.getInstance().loadNewInstance(triggerParam.getGlueSource());
                    jobHandler = new GlueHandler(originJobHandler, triggerParam.getGlueUpdatetime());
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    JobFileAppender.appendLog(logFileName, "init glue code failure, error msg:" + e.getMessage());
                    return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage());
                }
            }
        } else if (glueTypeEnum != null && glueTypeEnum.isScript()) {
            // valid old jobThread
            if (executorHandler != null && !(executorHandler.getHandler() instanceof ScriptGlueHandler && ((ScriptGlueHandler) executorHandler.getHandler()).getGlueUpdatetime() == triggerParam.getGlueUpdatetime())) {
                // change script or gluesource updated, need kill old thread
                removeOldReason = "change job source or glue type, and terminate the old job thread.";
                executorHandler = null;
                jobHandler = null;
            }

            // valid handler
            if (jobHandler == null) {
                jobHandler = new ScriptGlueHandler(triggerParam.getJobId(), triggerParam.getGlueUpdatetime(), triggerParam.getGlueSource(), GlueTypeEnum.match(triggerParam.getGlueType()));
            }
        } else {
            return new ReturnT<>(ReturnT.FAIL_CODE, "glueType[" + triggerParam.getGlueType() + "] is not valid.");
        }
        if (executorHandler == null) {
            executorHandler = GlueExecutor.registerJobThread(triggerParam.getJobId(), jobHandler, removeOldReason);
        }
        // push data to queue
        executorHandler.run(triggerParam);
        return new ReturnT<>(GlueExecContext.getXxlJobContext().getHandleCode(), GlueExecContext.getXxlJobContext().getHandleMsg(), GlueExecContext.getXxlJobContext().getHandlerResult());
    }


    public ReturnT<LogResult> log(LogParam logParam) {
        // log filename: logPath/yyyy-MM-dd/9999.log
        String logFileName = JobFileAppender.makeLogFileName(new Date(logParam.getLogDateTim()), logParam.getLogId());

        LogResult logResult = JobFileAppender.readLog(logFileName, logParam.getFromLineNum());
        return new ReturnT<LogResult>(logResult);
    }

}
